package com.lzh.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.lzh.constant.MQConstant;
import com.lzh.constant.RedisKey;
import com.lzh.constant.StatusConstant;
import com.lzh.domain.dto.LoginMessageDTO;
import com.lzh.domain.entity.AuthData;
import com.lzh.domain.entity.User;
import com.lzh.domain.vo.UserVO;
import com.lzh.mapper.UserMapper;
import com.lzh.producter.MQProducer;
import com.lzh.service.AuthLoginService;
import com.lzh.utils.IpUtil;
import com.lzh.utils.JwtUtils;
import com.lzh.utils.RedisUtils;
import com.lzh.utils.ResponseResult;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class AuthLoginServiceImpl implements AuthLoginService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    @Qualifier("mallchatExecutor")
    private ThreadPoolTaskExecutor executor ;

    @Resource
    private MQProducer mqProducer;

    @SneakyThrows
    public void testAsync(){
        //log.info("异步执行1 ==>"+Thread.currentThread().getName());
        AuthLoginService bean = SpringUtil.getBean(AuthLoginService.class);
        bean.testAsync2();
        CompletableFuture<String> res1 = CompletableFuture.supplyAsync(() -> {
            log.info("异步执行2 ==>"+Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "12";
        }, executor);



        CompletableFuture<String> res2 = CompletableFuture.supplyAsync(() -> {
            log.info("异步执行3 ==>" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "3";
        },executor);


        CompletableFuture.allOf(res1,res2).get(20, TimeUnit.SECONDS);
        System.out.println("res ==>"+res1.get()+res2.get());

    }

    @Override
    public Boolean verify(String token) {
        Long uid = jwtUtils.getUidOrNull(token);
        if(Objects.isNull(uid)){
            return false;
        }

        String redisToken  =   RedisUtils.getStr(RedisKey.getKey(RedisKey.USER_TOKEN, uid));
        return Objects.equals(redisToken, token);
    }

    @Override
    public void testAsync2() {

    }


    @Override
    public void login(HttpServletResponse response, String source, AuthResponse authResponse,String code) throws IOException {
        if (Objects.isNull(authResponse.getData())) {
            log.info("用户取消了授权{}", new Date());
            response.sendRedirect("http://localhost:/login");
            return;
        }

        //第三放授权数据回调
        log.info("授权数据回调{}", authResponse.getData());
        AuthData authData = JSONUtil.toBean(JSONUtil.toJsonStr(authResponse.getData()), AuthData.class);

        //第三方授权无效
        Optional.ofNullable(authData.getUuid()).orElseThrow(() -> new RuntimeException("第三方授权登录失败"));

        // 获取用户ip信息
        String ipAddress = IpUtil.getIp();
        String ipSource = IpUtil.getIp2region(ipAddress);
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUserName, authData.getUuid())
                .last("limit 1")
        );
        if (Objects.isNull(user)) {
            user = User.builder()
                    .name(authData.getNickname())
                    .userName(authData.getUuid())
                    .avatar(authData.getAvatar())
                    .ipInfo(ipSource)
                    .lastOptTime(new Date())
                    .createTime(new Date())
                    .build();
            userMapper.insert(user);
        } else {
            userMapper.update(new User(), new LambdaUpdateWrapper<User>()
                    .eq(User::getUserName, authData.getUuid())
                    .set(User::getName, authData.getNickname())
                    .set(User::getAvatar, authData.getAvatar())
                    .set(User::getLastOptTime, LocalDateTime.now())
                    .set(User::getUpdateTime, LocalDateTime.now())
            );
        }

        // 相当于传递的auth code
        mqProducer.sendMsg(MQConstant.LOGIN_MSG_TOPIC, new LoginMessageDTO(user.getId(),Integer.valueOf(code)));

        //通过websocket主动推送给前端
        //可以使用rocketmq推送数据


        String key = RedisKey.getKey(RedisKey.USER_TOKEN, authData.getUuid());
        //获取redis里的token
        String token = RedisUtils.getStr(key);
        if(StrUtil.isBlank(token)){
            //生成token
            token = jwtUtils.createToken(Long.valueOf(authData.getUuid()));
            RedisUtils.set(key, token, 5, TimeUnit.DAYS);
            response.sendRedirect("http://localhost:3000?token="+token);
            return;
        }
        response.sendRedirect("http://localhost:3000?token="+token);
        //response.sendRedirect("http://localhost:3000?token=");
    }

    @Override
    public ResponseResult<UserVO> getUserInfo(String token) {
        Long userId = Optional.ofNullable(jwtUtils.getUidOrNull(token)).orElseThrow(() -> new RuntimeException("token无效"));
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUserName, userId.toString())
                .eq(User::getStatus, StatusConstant.USER_ENABLE)
        );

        return ResponseResult.success(user.asViewObject(UserVO.class));
    }

    @Override
    public String userLogin(Long uuid) {
        String value = RedisKey.getKey(RedisKey.USER_TOKEN, uuid);
        /**
         * 判断是否是由于websocket断开后
         */
        if(StrUtil.isNotBlank(value)){
          return value;
        }
        /**
         * redis中已经不存在token，则重新生成token
         */
        value = jwtUtils.createToken(uuid);
        RedisUtils.set(RedisKey.getKey(RedisKey.USER_TOKEN, uuid), value, 7, TimeUnit.DAYS);
        return value;
    }


}
